home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 11587 / 11587.xpi / chrome / aviary.jar / content / upload.js < prev    next >
Text File  |  2009-07-09  |  12KB  |  353 lines

  1. /* Copyright (c) 2007-2009 Pearl Crescent, LLC.  All Rights Reserved. */
  2. /* vim: set sw=2 sts=2 ts=8 et syntax=javascript: */
  3.  
  4. var gAviaryUpload = 
  5. {
  6.   // If aOpenWithToolID is not zero, image is opened in app after uploading.
  7.   // aInputStream must be an nsIBinaryInputStream.
  8.   UploadStream: function(aContentType, aInputStream, aFileName, aOriginatingURL,
  9.                          aProgressMeter, aOpenWithToolID)
  10.   {
  11.     if (!aContentType || !aInputStream)
  12.     {
  13.       throw new Components.Exception("missing parameter",
  14.                                      Components.results.NS_ERROR_INVALID_ARG);
  15.     }
  16.  
  17.     if (aProgressMeter && aProgressMeter.IsCanceled())
  18.     {
  19.       aProgressMeter.Close(false, null);
  20.       return;
  21.     }
  22.  
  23.     var uploader = new AviaryFileUploader(aContentType, aInputStream, null,
  24.                                           aFileName, aOriginatingURL,
  25.                                           aProgressMeter, aOpenWithToolID);
  26.   },
  27.  
  28.   // If aOpenWithToolID is not zero, image is opened in app after uploading.
  29.   UploadByURL: function(aImageURL, aOpenWithToolID)
  30.   {
  31.     if (!aImageURL)
  32.     {
  33.       throw new Components.Exception("missing parameter",
  34.                                      Components.results.NS_ERROR_INVALID_ARG);
  35.     }
  36.  
  37.     var uploader = new AviaryFileUploader(null, null, aImageURL, null, null,
  38.                                           null, aOpenWithToolID);
  39.   },
  40.  
  41.   endOfObject: true
  42. };
  43.  
  44. // It would be better to nest this within gAviaryUpload.
  45. function AviaryFileUploader(aContentType, aInputStream, aImageURL, aFileName,
  46.                             aOriginatingURL, aProgressMeter, aOpenWithToolID)
  47. {
  48.   this.init(aContentType, aInputStream, aImageURL, aFileName, aOriginatingURL,
  49.             aProgressMeter, aOpenWithToolID);
  50. }
  51.  
  52. AviaryFileUploader.prototype =
  53. {
  54.   kUploadDestURL: "",
  55.   kFileDetailsURL: "",
  56.   kUploadDestURLSuffix: "/apps/xmlapi/receiver.aspx",
  57.   kFileDetailsURLSuffix: "/creation?fguid=",
  58.   kUploadSource: "upload",
  59.   kUploadAUID: "aviaryframework",
  60.   kUploadAndEditAUID: "aviarysourcefile",
  61.   kMIMEBoundaryPrefix: "--------AVIARY_",
  62.   kEndOfLineStr: "\r\n",
  63.  
  64.   mPearlUtil: null,
  65.   mOpenWithToolID: 0,
  66.   mRequest: null,
  67.   mRequestHasBeenAborted: false,
  68.   mMIMEBoundary: null,
  69.   mProgressMeter: null,
  70.  
  71.   init: function(aContentType, aInputStream, aImageURL, aFileName,
  72.                  aOriginatingURL, aProgressMeter, aOpenWithToolID)
  73.   {
  74.     if (!aImageURL && (!aContentType || !aInputStream))
  75.     {
  76.       throw new Components.Exception("missing parameter",
  77.                                      Components.results.NS_ERROR_INVALID_ARG);
  78.     }
  79.  
  80.     this.mPearlUtil = com.aviary.talon.pearlutil;
  81.     this.mProgressMeter = aProgressMeter;
  82.     this.mOpenWithToolID = aOpenWithToolID;
  83.     this.mMIMEBoundary = this.kMIMEBoundaryPrefix + Math.random();
  84.  
  85.     var serverPrefix = this.mPearlUtil.GetASCIIPref("aviary.serverPrefix");
  86.     if (serverPrefix)
  87.     {
  88.       this.kUploadDestURL = serverPrefix + this.kUploadDestURLSuffix;
  89.       this.kFileDetailsURL = serverPrefix + this.kFileDetailsURLSuffix;
  90.     }
  91. //  this.kUploadDestURL = "http://quartz/dist/aviary/upload/";
  92.  
  93.     if (aProgressMeter)
  94.     {
  95.       var str = this.mPearlUtil.GetLocalizedString("SAVING_TO_ROOKERY");
  96.       aProgressMeter.SetLabel(str);
  97.  
  98.       var self = this;
  99.       aProgressMeter.SetCancelFunction(function() { self.OnCancel(); });
  100.     }
  101.  
  102.     if (!aImageURL)
  103.     {
  104.       if (!aFileName)
  105.       {
  106.         // Use default file name.  Determine extension based on content type.
  107.         var fileExt = "";
  108.         if ("image/png" == aContentType)
  109.           fileExt = ".png";
  110.         else if ("image/jpg" == aContentType)
  111.           fileExt = ".jpg";
  112.         else if ("image/gif" == aContentType)
  113.           fileExt = ".gif";
  114.       
  115.         aFileName = this.mPearlUtil
  116.                         .GetLocalizedString("SUGGESTED_FILE_PREFIX") + fileExt;
  117.       }
  118.  
  119.       if (aProgressMeter)
  120.         aProgressMeter.SetName(aFileName);
  121.     }
  122.  
  123.     // Create and initialize request.
  124.     this.mRequest = new XMLHttpRequest();
  125.  
  126.     var self = this;
  127.     this.mRequest.onload = function() { self.onLoad(self); }
  128.     this.mRequest.onerror = function() { self.onError(self); }
  129.     this.mRequest.onuploadprogress =
  130.                      function(aEvent) { self.onUploadProgress(self, aEvent); }
  131.  
  132.     this.mRequest.open("POST", this.kUploadDestURL, true);
  133.     com.aviary.talon.request.
  134.                         EnsureCookiesWillBeSent(this.mRequest.channel, null);
  135.     this.mRequest.setRequestHeader("Content-type",
  136.                         "multipart/form-data; boundary=" + this.mMIMEBoundary);
  137.     this.mRequest.overrideMimeType("application/xml");
  138.  
  139.     // Arrange to send a file upload form post.
  140.     const kMSCID = "@mozilla.org/io/multiplex-input-stream;1";
  141.     var multiStream = Components.classes[kMSCID]
  142.                 .createInstance(Components.interfaces.nsIMultiplexInputStream);
  143.     var s = this.createInputStringBodyPart("source", this.kUploadSource);
  144.     var auid = (0 != this.mOpenWithToolID) ? this.kUploadAndEditAUID
  145.                                            : this.kUploadAUID;
  146.     s += this.createInputStringBodyPart("auid", auid);
  147.     multiStream.appendStream(this.createStringStream(s));
  148.  
  149.     var endOfMIMESuffix = "";
  150.     if (aImageURL)
  151.     {
  152.       // To cause an error, use s += on next line.
  153.       s = this.createInputStringBodyPart("url", aImageURL);
  154.       multiStream.appendStream(this.createStringStream(s));
  155.     }
  156.     else
  157.     {
  158.       if (aOriginatingURL)
  159.       {
  160.         s = this.createInputStringBodyPart("originalurl", aOriginatingURL);
  161.         multiStream.appendStream(this.createStringStream(s));
  162.       }
  163.  
  164.       var filePrefix = "--" + this.mMIMEBoundary + this.kEndOfLineStr
  165.                        + "Content-Disposition: form-data; name=\"file\"; "
  166.                        + "filename=\"" + aFileName + "\"" + this.kEndOfLineStr
  167.                        + "Content-type: " + aContentType + this.kEndOfLineStr
  168.                        + this.kEndOfLineStr;
  169.       multiStream.appendStream(this.createStringStream(filePrefix));
  170.  
  171.       /*
  172.        * Ensure that the image stream is seekable (required by NoScript and
  173.        * possibly by Necko).
  174.        */
  175.       var storageStream = Components.classes["@mozilla.org/storagestream;1"] 
  176.                         .createInstance(Components.interfaces.nsIStorageStream);
  177.       storageStream.init(32768, -1, null);
  178.       var outputStream = storageStream.getOutputStream(0);
  179.       const kMaxBlockSize = 65536;
  180.       var remaining = aInputStream.available();
  181.       while (remaining > 0)
  182.       {
  183.         var count = (remaining > kMaxBlockSize) ? kMaxBlockSize : remaining;
  184.         var b = aInputStream.readBytes(count);
  185.         outputStream.write(b, count);
  186.         remaining -= count;
  187.       }
  188.       outputStream.close();
  189.       multiStream.appendStream(storageStream.newInputStream(0));
  190.  
  191.       endOfMIMESuffix += this.kEndOfLineStr;
  192.     }
  193.  
  194.     endOfMIMESuffix += "--" + this.mMIMEBoundary + this.kEndOfLineStr;
  195.     multiStream.appendStream(this.createStringStream(endOfMIMESuffix));
  196.     this.mRequest.send(multiStream);
  197.   },
  198.   
  199.   onUploadProgress: function(aThisObj, aEvent)
  200.   {
  201.     var percentDone = Math.floor(100 * (aEvent.position / aEvent.totalSize));
  202.     if (percentDone > 100)
  203.       percentDone = 100; // TODO: position exceeds totalSize; FF bug??
  204. //    dump("onUploadProgress: " + percentDone + "% of " + aEvent.totalSize + "\n");
  205.  
  206.     if (aThisObj.mProgressMeter)
  207.       aThisObj.mProgressMeter.SetValue(percentDone);
  208.   },
  209.  
  210.   onLoad: function(aThisObj)
  211.   {
  212.     if (aThisObj.mRequestHasBeenAborted)
  213.       return;
  214.  
  215.     if (aThisObj.mProgressMeter)
  216.       aThisObj.mProgressMeter.SetIsCancelable(false); // Too late to cancel.
  217.  
  218.     var succeeded = false;
  219.     try {
  220.       const knsIHttpChannel = Components.interfaces.nsIHttpChannel;
  221.       var channel = aThisObj.mRequest.channel.QueryInterface(knsIHttpChannel);
  222.       succeeded = channel.requestSucceeded;
  223.     } catch(e) { dump("onLoad: " + e + "\n"); }
  224.  
  225. // dump("response text:\n" + aThisObj.mRequest.responseText + "\n");
  226.     var fguid = null;
  227.     if (succeeded)
  228.     {
  229.       succeeded = false;
  230.       var responseNode = aThisObj.getResponseNode(aThisObj.mRequest);
  231.       if (responseNode)
  232.       {
  233.         var fileNode = aThisObj.mPearlUtil
  234.                           .PearlGetFirstElementByTagName(responseNode, "file");
  235.         if (fileNode)
  236.         {
  237.           fguid = aThisObj.mPearlUtil.GetFirstChildText(fileNode, "fileguid");
  238.           succeeded = (fguid != null && fguid.length > 0);
  239.         }
  240.       }
  241.     }
  242.  
  243.     if (!succeeded)
  244.     {
  245.       aThisObj.onError(aThisObj);
  246.       return;
  247.     }
  248.  
  249.     if (aThisObj.mProgressMeter)
  250.     {
  251.       aThisObj.mProgressMeter.SetValue(100);
  252.       aThisObj.mProgressMeter.Close(true, "IMAGE_SAVED");  // fade out
  253.     }
  254.  
  255.     if (0 != aThisObj.mOpenWithToolID)
  256.     {
  257.       gAviaryMain.LaunchAppByToolID(aThisObj.mOpenWithToolID, fguid,
  258.                                     null, null);
  259.     }
  260.     else
  261.     {
  262.       var detailsURL = this.kFileDetailsURL + encodeURIComponent(fguid);
  263.       gAviaryMain.OpenInNewTab(detailsURL, null);
  264.     }
  265.   },
  266.  
  267.   onError: function(aThisObj)
  268.   {
  269.     if (aThisObj.mProgressMeter)
  270.       aThisObj.mProgressMeter.Close(false, null);  // close immediately
  271.  
  272.     if (aThisObj.mRequestHasBeenAborted)     // Suppress errors if canceled.
  273.       return;
  274.  
  275.     // If possible, get detailed information from <failedfiles> within response.
  276.     var errMsg;
  277.     var responseNode = aThisObj.getResponseNode(aThisObj.mRequest);
  278.     if (responseNode)
  279.     {
  280.       var node = aThisObj.mPearlUtil
  281.                     .PearlGetFirstElementByTagName(responseNode, "failedfile");
  282.       if (node)
  283.       {
  284.         errMsg = aThisObj.mPearlUtil.GetNodeText(node);
  285.         if (!errMsg)
  286.           errMsg = node.getAttribute("reason");
  287.       }
  288.     }
  289.  
  290.     // TODO: fit this error message within a caller-provider message.
  291.     if (!errMsg)
  292.       errMsg = "Upload failed."; // TODO: L10n
  293.     aThisObj.mPearlUtil.Alert(window, errMsg);
  294.   },
  295.  
  296.   OnCancel: function()
  297.   {
  298.     this.mRequestHasBeenAborted = true;
  299.  
  300.     if (this.mProgressMeter)
  301.     {
  302.       this.mProgressMeter.Close(false, null);  // close immediately
  303.       this.mProgressMeter = null;
  304.     }
  305.  
  306.     if (this.mRequest)
  307.       this.mRequest.abort();
  308.   },
  309.  
  310.   getResponseNode: function(aRequest)
  311.   {
  312.     var responseNode = null;
  313.     if (aRequest && aRequest.responseXML)
  314.     {
  315.       var responseDoc = aRequest.responseXML;
  316.       if (responseDoc && responseDoc.firstChild &&
  317.           responseDoc.firstChild.nodeName == "response")
  318.       {
  319.           responseNode = responseDoc.firstChild;
  320.       }
  321.     }
  322.  
  323.     return responseNode;
  324.   },
  325.  
  326.   createStringStream: function(aStr)
  327.   {
  328.     if (!aStr)
  329.       return null;
  330.  
  331.     const kSISCID = "@mozilla.org/io/string-input-stream;1";
  332.     var strStream = Components.classes[kSISCID]
  333.                 .createInstance(Components.interfaces.nsIStringInputStream);
  334.     strStream.setData(aStr, aStr.length);
  335.     return strStream;
  336.   },
  337.  
  338.   createInputStringBodyPart: function(aName, aValue)
  339.   {
  340.     if (!aName || !aValue)
  341.       return "";
  342.  
  343.     var s = "--" + this.mMIMEBoundary + this.kEndOfLineStr
  344.             + "Content-Disposition: form-data; name=\"" + aName + "\""
  345.             + this.kEndOfLineStr + this.kEndOfLineStr;
  346.     s += aValue + this.kEndOfLineStr;
  347.     return s;
  348.   },
  349.  
  350.   endOfObject: true
  351. }
  352.  
  353.